/*
* Qcommon.java
* Copyright 2003
* 
* $Id: Qcommon.java,v 1.22 2006/02/13 10:05:55 hzi Exp $
*/
/*
Copyright (C) 1997-2001 Id Software, Inc.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
using System;
using System.IO;
using System.Text;
using Suake2.UI.client;
using Suake2.UI.game;
using Suake2.UI.server;
using Suake2.UI.sys;
using Suake2.UI.util;

namespace Suake2.UI.qcommon
{
    /// <summary> Qcommon contains some  basic routines for the game engine
    /// namely initialization, shutdown and frame generation.
    /// </summary>
    public sealed class Qcommon : Globals
    {
        //UPGRADE_NOTE: Final was removed from the declaration of 'BUILDSTRING '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
        //UPGRADE_ISSUE: Method 'java.lang.System.getProperty' was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1000_javalangSystem'"
        //public static readonly System.String BUILDSTRING = "Java " + System_Renamed.getProperty("java.version"); 
        public static readonly String BUILDSTRING = "c# 3.5";
        //UPGRADE_NOTE: Final was removed from the declaration of 'CPUSTRING '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
        //UPGRADE_TODO: Method 'java.lang.System.getProperty' was converted to 'System.Environment.GetEnvironmentVariable' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javalangSystemgetProperty_javalangString'"
        public static readonly String CPUSTRING = Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE");

        /// <summary> This function initializes the different subsystems of
        /// the game engine. The setjmp/longjmp mechanism of the original
        /// was replaced with exceptions.
        /// </summary>
        /// <param name="args">the original unmodified command line arguments
        /// </param>
        public static void Init(String[] args)
        {
            try
            {
                // prepare enough of the subsystems to handle
                // cvar and command buffer management
                Com.InitArgv(args);

                Cbuf.Init();

                Cmd.Init();
                Cvar.Init();

                Key.Init();

                // we need to add the early commands twice, because
                // a basedir or cddir needs to be set before execing
                // config files, but we want other parms to override
                // the settings of the config files
                Cbuf.AddEarlyCommands(false);
                Cbuf.Execute();

                if (dedicated.value_Renamed != 1.0f)
                    Suake2.Q2Dialog.Status = "initializing filesystem...";

                FS.InitFilesystem();

                if (dedicated.value_Renamed != 1.0f)
                    Suake2.Q2Dialog.Status = "loading config...";

                reconfigure(false);

                FS.setCDDir(); // use cddir from config.cfg
                FS.markBaseSearchPaths(); // mark the default search paths

                if (dedicated.value_Renamed != 1.0f)
                    Suake2.Q2Dialog.testQ2Data(); // test for valid baseq2

                reconfigure(true); // reload default.cfg and config.cfg

                //
                // init commands and vars
                //
                Cmd.AddCommand("error", Com.Error_f);

                host_speeds = Cvar.Get("host_speeds", "0", 0);
                log_stats = Cvar.Get("log_stats", "0", 0);
                developer = Cvar.Get("developer", "0", CVAR_ARCHIVE);
                timescale = Cvar.Get("timescale", "0", 0);
                fixedtime = Cvar.Get("fixedtime", "0", 0);
                logfile_active = Cvar.Get("logfile", "0", 0);
                showtrace = Cvar.Get("showtrace", "0", 0);
                dedicated = Cvar.Get("dedicated", "0", CVAR_NOSET);
                String s = Com.sprintf("%4.2f %s %s %s",
                                       new Vargs(4).add(VERSION).add(CPUSTRING).add(__DATE__).add(BUILDSTRING));

                Cvar.Get("version", s, CVAR_SERVERINFO | CVAR_NOSET);

                if (dedicated.value_Renamed != 1.0f)
                    Suake2.Q2Dialog.Status = "initializing network subsystem...";

                NET.Init(); //ok
                Netchan.Netchan_Init(); //ok

                if (dedicated.value_Renamed != 1.0f)
                    Suake2.Q2Dialog.Status = "initializing server subsystem...";
                SV_MAIN.SV_Init(); //ok

                if (dedicated.value_Renamed != 1.0f)
                    Suake2.Q2Dialog.Status = "initializing client subsystem...";

                CL.Init();

                // add + commands from command line
                if (!Cbuf.AddLateCommands())
                {
                    // if the user didn't give any commands, run default action
                    if (dedicated.value_Renamed == 0)
                        Cbuf.AddText("d1\n");
                    else
                        Cbuf.AddText("dedicated_start\n");

                    Cbuf.Execute();
                }
                else
                {
                    // the user asked for something explicit
                    // so drop the loading plaque
                    SCR.EndLoadingPlaque();
                }

                Com.Printf("====== Quake2 Initialized ======\n\n");

                // save config when configuration is completed
                CL.WriteConfiguration();

                if (dedicated.value_Renamed != 1.0f)
                    Suake2.Q2Dialog.Dispose();
            }
            catch (longjmpException e)
            {
                Sys.Error("Error during initialization");
            }
        }

        /// <summary> Trigger generation of a frame for the given time. The setjmp/longjmp
        /// mechanism of the original was replaced with exceptions.
        /// </summary>
        /// <param name="msec">the current game time
        /// </param>
        public static void Frame(int msec)
        {
            try
            {
                if (log_stats.modified)
                {
                    log_stats.modified = false;

                    if (log_stats.value_Renamed != 0.0f)
                    {
                        if (log_stats_file != null)
                        {
                            try
                            {
                                log_stats_file.Close();
                            }
                            catch (IOException e)
                            {
                            }
                            log_stats_file = null;
                        }

                        try
                        {
                            //UPGRADE_TODO: Constructor 'java.io.FileWriter.FileWriter' was converted to 'System.IO.StreamWriter' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioFileWriterFileWriter_javalangString'"
                            //UPGRADE_TODO: Class 'java.io.FileWriter' was converted to 'System.IO.StreamWriter' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioFileWriter'"
                            log_stats_file = new StreamWriter("stats.log", false, Encoding.Default);
                        }
                        catch (IOException e)
                        {
                            log_stats_file = null;
                        }
                        if (log_stats_file != null)
                        {
                            try
                            {
                                log_stats_file.Write("entities,dlights,parts,frame time\n");
                            }
                            catch (IOException e)
                            {
                            }
                        }
                    }
                    else
                    {
                        if (log_stats_file != null)
                        {
                            try
                            {
                                log_stats_file.Close();
                            }
                            catch (IOException e)
                            {
                            }
                            log_stats_file = null;
                        }
                    }
                }

                if (fixedtime.value_Renamed != 0.0f)
                {
                    //UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
                    msec = (int) fixedtime.value_Renamed;
                }
                else if (timescale.value_Renamed != 0.0f)
                {
                    msec = (int) (msec*timescale.value_Renamed);
                    if (msec < 1)
                        msec = 1;
                }

                if (showtrace.value_Renamed != 0.0f)
                {
                    Com.Printf("%4i traces  %4i points\n", new Vargs(2).add(c_traces).add(c_pointcontents));


                    c_traces = 0;
                    c_brush_traces = 0;
                    c_pointcontents = 0;
                }

                Cbuf.Execute();

                int time_before = 0;
                int time_between = 0;
                int time_after = 0;

                if (host_speeds.value_Renamed != 0.0f)
                    time_before = Timer.Milliseconds();

                Com.debugContext = "SV:";
                SV_MAIN.SV_Frame(msec);

                if (host_speeds.value_Renamed != 0.0f)
                    time_between = Timer.Milliseconds();

                Com.debugContext = "CL:";
                CL.Frame(msec);

                if (host_speeds.value_Renamed != 0.0f)
                {
                    time_after = Timer.Milliseconds();

                    int all = time_after - time_before;
                    int sv = time_between - time_before;
                    int cl = time_after - time_between;
                    int gm = time_after_game - time_before_game;
                    int rf = time_after_ref - time_before_ref;
                    sv -= gm;
                    cl -= rf;

                    Com.Printf("all:%3i sv:%3i gm:%3i cl:%3i rf:%3i\n",
                               new Vargs(5).add(all).add(sv).add(gm).add(cl).add(rf));
                }
            }
            catch (longjmpException e)
            {
                //UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Throwable.toString' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'"
                Com.DPrintf("lonjmp exception:" + e);
            }
        }

        internal static void reconfigure(bool clear)
        {
            String dir = Cvar.Get("cddir", "", CVAR_ARCHIVE).string_Renamed;
            Cbuf.AddText("exec default.cfg\n");
            Cbuf.AddText("bind MWHEELUP weapnext\n");
            Cbuf.AddText("bind MWHEELDOWN weapprev\n");
            Cbuf.AddText("bind w +forward\n");
            Cbuf.AddText("bind s +back\n");
            Cbuf.AddText("bind a +moveleft\n");
            Cbuf.AddText("bind d +moveright\n");
            Cbuf.Execute();
            Cvar.Set("vid_fullscreen", "0");
            Cbuf.AddText("exec config.cfg\n");

            Cbuf.AddEarlyCommands(clear);
            Cbuf.Execute();
            if (!("".Equals(dir)))
                Cvar.Set("cddir", dir);
        }
    }
}